package task

import (
	"context"
	"errors"
	"fmt"
	"github.com/robfig/cron/v3"
	"go-task/common"
	"go-task/domain/model"
	"sync"
	"time"
)

var (
	TM *TimeTaskManager
)

type TimeTaskManager struct {
	cron  *cron.Cron
	tasks map[string]*TaskExecutor
	mu    sync.RWMutex
}

type TaskExecutor struct {
	TaskId      string
	ctx         context.Context
	cancel      context.CancelFunc
	cronEntryID cron.EntryID
	mu          sync.Mutex
}

type ErrorHandler func(taskID string, err error)

func InitTimeTaskManager() {
	TM = NewTimeTaskManager()
	TM.LoadPersistentTasks()
}

// NewTimeTaskManager 创建新任务管理器
func NewTimeTaskManager() *TimeTaskManager {
	c := cron.New(cron.WithSeconds())
	c.Start()

	return &TimeTaskManager{
		cron:  c,
		tasks: make(map[string]*TaskExecutor),
	}
}

func (tm *TimeTaskManager) AddTask(ctx context.Context, timeTask *model.TimeTask) error {
	tm.mu.Lock()
	defer tm.mu.Unlock()

	taskId := timeTask.TaskId

	if _, exists := tm.tasks[taskId]; exists {
		return errors.New("taskId already exists")
	}

	// 创建任务上下文
	taskCtx, cancel := context.WithCancel(ctx)
	newTask := &TaskExecutor{
		TaskId: taskId,
		ctx:    taskCtx,
		cancel: cancel,
	}

	// 包装任务函数
	wrappedFunc := func() {
		defer func() {
			if r := recover(); r != nil {
				err := fmt.Errorf("task panic: %v", r)
				tm.errorHandler(taskId, err)
			}
		}()

		startTime := time.Now()
		err := tm.sendTask(timeTask)
		execDuration := time.Since(startTime)

		if err != nil {
			tm.errorHandler(taskId, err)
		}

		common.Logger.Infof("Task %s executed in %v", taskId, execDuration)
		if common.ONETIME == timeTask.TaskType {
			stopErr := tm.StopTask(taskId)
			if stopErr != nil {
				common.Logger.Errorf("Task %s stop error: %v", taskId, stopErr)
			}
		}
	}

	entryID, err := tm.cron.AddFunc(timeTask.CronExpr, wrappedFunc)
	if err != nil {
		return fmt.Errorf("invalid cron expression: %w", err)
	}
	newTask.cronEntryID = entryID
	tm.tasks[taskId] = newTask
	return nil
}

// StopTask 停止任务
func (tm *TimeTaskManager) StopTask(taskId string) error {
	tm.mu.Lock()
	defer tm.mu.Unlock()

	task, exists := tm.tasks[taskId]
	if !exists {
		return nil
	}

	tm.cron.Remove(task.cronEntryID)
	delete(tm.tasks, taskId)
	return nil
}

// LoadPersistentTasks 加载持久化任务
func (tm *TimeTaskManager) LoadPersistentTasks() {
	var timeTask model.TimeTask
	list, err := timeTask.QueryList()
	if err != nil {
		common.Logger.Errorf("load time task list failed: %v", err)
		return
	}

	for _, task := range list {
		if common.TASK_RUN == task.TaskStatus {
			taskErr := tm.AddTask(context.Background(), &task)
			if taskErr != nil {
				common.Logger.Errorf("Task %s add failed: %v", task.TaskId, taskErr)
			}
		}
	}
}

func (tm *TimeTaskManager) errorHandler(taskID string, err error) {
	common.Logger.Infof("Task %s failed: %v", taskID, err)
}

func (tm *TimeTaskManager) sendTask(timeTask *model.TimeTask) error {
	common.Logger.Infof("Task %s send to task executor", timeTask.TaskId)
	TaskManager.sendTimeTask(timeTask)
	return nil
}
